/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the  "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*
 * $Id$
 */
package wx.xml.xalan.xalan.templates;

import java.util.Vector;

import javax.xml.transform.TransformerException;

import wx.xml.xalan.xalan.res.XSLMessages;
import wx.xml.xalan.xalan.res.XSLTErrorResources;
import wx.xml.xalan.xalan.transformer.TransformerImpl;
import wx.xml.xalan.xml.utils.QName;

/**
 * Implement xsl:use.
 * This acts as a superclass for ElemCopy, ElemAttributeSet,
 * ElemElement, and ElemLiteralResult, on order to implement
 * shared behavior the use-attribute-sets attribute.
 *
 * @xsl.usage advanced
 * @see <a href="http://www.w3.org/TR/xslt#attribute-sets">attribute-sets in XSLT Specification</a>
 */
public class ElemUse extends ElemTemplateElement {
    static final long serialVersionUID = 5830057200289299736L;

    /**
     * The value of the "use-attribute-sets" attribute.
     *
     * @serial
     */
    private QName m_attributeSetsNames[] = null;

    /**
     * Set the "use-attribute-sets" attribute.
     * Attribute sets are used by specifying a use-attribute-sets
     * attribute on xsl:element, xsl:copy (see [7.5 Copying]) or
     * xsl:attribute-set elements. The value of the use-attribute-sets
     * attribute is a whitespace-separated list of names of attribute
     * sets. Each name is specified as a QName, which is expanded as
     * described in [2.4 Qualified Names].
     *
     * @param v The value to set for the "use-attribute-sets" attribute.
     */
    public void setUseAttributeSets(Vector v) {

        int n = v.size();

        m_attributeSetsNames = new QName[n];

        for (int i = 0; i < n; i++) {
            m_attributeSetsNames[i] = (QName) v.elementAt(i);
        }
    }

    /**
     * Get the "use-attribute-sets" attribute.
     * Attribute sets are used by specifying a use-attribute-sets
     * attribute on xsl:element, xsl:copy (see [7.5 Copying]) or
     * xsl:attribute-set elements, or a xsl:use-attribute-sets attribute on
     * Literal Result Elements.
     * The value of the use-attribute-sets
     * attribute is a whitespace-separated list of names of attribute
     * sets. Each name is specified as a QName, which is expanded as
     * described in [2.4 Qualified Names].
     *
     * @return The value of the "use-attribute-sets" attribute.
     */
    public QName[] getUseAttributeSets() {
        return m_attributeSetsNames;
    }

    /**
     * Set the "use-attribute-sets" attribute.
     * Attribute sets are used by specifying a use-attribute-sets
     * attribute on xsl:element, xsl:copy (see [7.5 Copying]) or
     * xsl:attribute-set elements. The value of the use-attribute-sets
     * attribute is a whitespace-separated list of names of attribute
     * sets. Each name is specified as a QName, which is expanded as
     * described in [2.4 Qualified Names].
     *
     * @param v The value to set for the "use-attribute-sets" attribute.
     */
    public void setUseAttributeSets(QName[] v) {
        m_attributeSetsNames = v;
    }

    /**
     * Add the attributes from the named attribute sets to the attribute list.
     * TODO: Error handling for: "It is an error if there are two attribute sets
     * with the same expanded-name and with equal import precedence and that both
     * contain the same attribute unless there is a definition of the attribute
     * set with higher import precedence that also contains the attribute."
     *
     * @param transformer non-null reference to the the current transform-time state.
     * @param stylesheet  The owning root stylesheet
     * @throws TransformerException
     */
    public void applyAttrSets(
        TransformerImpl transformer, StylesheetRoot stylesheet)
        throws TransformerException {
        applyAttrSets(transformer, stylesheet, m_attributeSetsNames);
    }

    /**
     * Add the attributes from the named attribute sets to the attribute list.
     * TODO: Error handling for: "It is an error if there are two attribute sets
     * with the same expanded-name and with equal import precedence and that both
     * contain the same attribute unless there is a definition of the attribute
     * set with higher import precedence that also contains the attribute."
     *
     * @param transformer        non-null reference to the the current transform-time state.
     * @param stylesheet         The owning root stylesheet
     * @param attributeSetsNames List of attribute sets names to apply
     * @throws TransformerException
     */
    private void applyAttrSets(
        TransformerImpl transformer, StylesheetRoot stylesheet, QName attributeSetsNames[])
        throws TransformerException {

        if (null != attributeSetsNames) {
            int nNames = attributeSetsNames.length;

            for (int i = 0; i < nNames; i++) {
                QName          qname    = attributeSetsNames[i];
                java.util.List attrSets = stylesheet.getAttributeSetComposed(qname);

                if (null != attrSets) {
                    int nSets = attrSets.size();

                    // Highest priority attribute set will be at the top,
                    // so process it last.
                    for (int k = nSets - 1; k >= 0; k--) {
                        ElemAttributeSet attrSet =
                            (ElemAttributeSet) attrSets.get(k);

                        attrSet.execute(transformer);
                    }
                } else {
                    throw new TransformerException(
                        XSLMessages.createMessage(XSLTErrorResources.ER_NO_ATTRIB_SET,
                            new Object[]{qname}), this);
                }
            }
        }
    }

    /**
     * Copy attributes specified by use-attribute-sets to the result tree.
     * Specifying a use-attribute-sets attribute is equivalent to adding
     * xsl:attribute elements for each of the attributes in each of the
     * named attribute sets to the beginning of the content of the element
     * with the use-attribute-sets attribute, in the same order in which
     * the names of the attribute sets are specified in the use-attribute-sets
     * attribute. It is an error if use of use-attribute-sets attributes
     * on xsl:attribute-set elements causes an attribute set to directly
     * or indirectly use itself.
     *
     * @param transformer non-null reference to the the current transform-time state.
     * @throws TransformerException
     */
    public void execute(
        TransformerImpl transformer)
        throws TransformerException {

        if (null != m_attributeSetsNames) {
            applyAttrSets(transformer, getStylesheetRoot(),
                m_attributeSetsNames);
        }

    }
}
